package com.vclee.fast.controller;

import com.vclee.fast.integration.imserver.XunFeiService;
import com.vclee.fast.utils.sdk.WxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.vclee.fast.utils.CipherUtils;
import com.vclee.fast.utils.CommonUtils;
import com.vclee.fast.utils.JwtUtils;
import com.vclee.fast.utils.SnowUtils;
import com.vclee.fast.utils.aspect.OpenServe;
import com.vclee.fast.utils.aspect.SysLog;
import com.vclee.fast.utils.cache.RedisDB;
import com.vclee.fast.utils.exception.Assert;
import com.vclee.fast.utils.exception.R;
import com.vclee.fast.utils.model.Bson;
import com.vclee.fast.utils.sdk.AliUtil;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


@OpenServe
@RestController
@RequestMapping("openapi-service")
public class ApiOpenController {

    // 获取RSA公钥后,保存私钥的前缀与有效时间
    private static final String REDIS_RSA_PREFIX = "ENV_RSA_";
    private static final Integer REDIS_RSA_VALID_TIME = 30;
    private static final Logger logger = LoggerFactory.getLogger(ApiOpenController.class);

    // @SysLog("获取RSA公钥")
    @PostMapping("/env/getRsaPublicKey")
    public R getRsaPublicKey() {
        Map<String, String> map = Objects.requireNonNull(CipherUtils.rsaKeys());
        String privateKey = map.get("privateKey");
        String publicKey = map.get("publicKey");
        String publicId = SnowUtils.getStrKey();
        RedisDB.set(REDIS_RSA_PREFIX + publicId, privateKey, REDIS_RSA_VALID_TIME);
        Bson result = new Bson();
        result.put("publicKey", publicKey);
        result.put("publicId", publicId);
        return R.ok(result);
    }

    // @SysLog("对等加密信息上报")
    @PostMapping("/env/reportPayload")
    public R reportPayload(@RequestBody Bson params) {
        String encData = params.getString("encData");
        String publicId = params.getString("publicId");
        String privateKey = RedisDB.get(REDIS_RSA_PREFIX + publicId, String.class);
        String aesKey = Objects.requireNonNull(CipherUtils.rsaDecrypt(encData, privateKey));
        Assert.claim(aesKey.length() != 16, "aesKey不合法");
        String accessToken = JwtUtils.createAccessToken(aesKey);
        return R.ok(accessToken);
    }

    // @SysLog("刷新accessToken")
    @PostMapping("/env/refreshAccessToken")
    public R refreshAccessToken() {
        return R.ok(JwtUtils.refreshAccessToken());
    }
    @SysLog("阿里OSS获取票据")
    @PostMapping("aliUtil/getOssTicket")
    public R getOssTicket(@RequestBody Bson params) {
        return R.ok(AliUtil.getOssTicket(params.getString("filename")));
    }

    @SysLog("阿里发送验证码")
    @PostMapping("aliUtil/sendCaptcha")
    public R sendCaptcha(@RequestBody Bson params) {
        String mobile = params.getString("mobile");
        String template = "SMS_474865651";
        Bson param = new Bson();
        param.put("code", CommonUtils.generatorAuthCode());
        return R.ok(AliUtil.sendSms(mobile,template,"富侨百城万店",param));
    }

    @SysLog("微信小程序登录CODE换取OPENID及UNIONID")
    @PostMapping(value = "wxUtil/wxAppletLogin")
    public R wxAppletLogin(@RequestBody Bson params) {
        String code = params.getString("code");
        String appid = params.getString("appid");
        String secret = params.getString("secret");
        if (Assert.isBlank(secret)) {
            secret = ""; // FIXME 通过appid获取secret
        }
        return R.ok(WxUtil.wxAppletLogin(code, appid, secret));
    }

    @SysLog("微信小程序使用code换取手机号")
    @PostMapping(value = "wxUtil/wxAppletGetMobile")
    public R wxAppletGetMobile(@RequestBody Bson params) {
        String code = params.getString("code");
        String appid = params.getString("appid");
        String secret = params.getString("secret");
        if (Assert.isBlank(secret)) {
            secret = ""; // FIXME 通过appid获取secret
        }
        return R.ok(WxUtil.wxAppletGetMobile(code, appid, secret));
    }

    @SysLog("小程序二维码生成")
    @PostMapping("/createMinQrCode")
    public R createMinQrCode(@RequestBody Bson params) {
        String data = params.getString("data"); // 数据
        String path = params.getString("path"); // 路径
        String width = params.getString("width"); // 宽度
        String appid = params.getString("appid"); // appid
        String secret = "";
        WxUtil.createAppletQrCode(data,path,width,appid,secret);
        return R.ok();
    }


    /**
     * 微信公众号地址配置验证通知
     *
     * @param weChat 微信通知的参数
     * @param appid  微信通知的appid在配置中心进行配置
     */
    @GetMapping(value = "wxUtil/wxGzNotify/{appid}", produces = "application/xml;charset=UTF-8")
    public String wxGzNotifyVerify(@RequestParam Map<String, String> weChat, @PathVariable String appid) { // 该接口只做验证
        logger.info("收到事件验证请求：appid{},请求参数:{}", appid, weChat);
        String signature = weChat.get("signature"); // 微信加密签名
        String timestamp = weChat.get("timestamp"); // 时间戳
        String nonce = weChat.get("nonce");// 随机数
        String echostr = weChat.get("echostr");// 随机字符串
        boolean verify = false;
        try {
            // 通过检验signature对请求进行校验，若校验成功则原样返回echostr，表示接入成功，否则接入失败 其中verify为配置的字符串
            String[] arr = new String[]{"verify", timestamp, nonce};
            String str = Arrays.stream(arr).sorted().collect(Collectors.joining());
            char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes(StandardCharsets.UTF_8));
            byte[] md = mdTemp.digest();
            int k = 0;
            int j = md.length;
            char[] buf = new char[j * 2];
            for (byte byte0 : md) {
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            verify = new String(buf).equals(signature);
        } catch (Exception e) {
            logger.error("微信地址配置算法校验异常:" + e.getMessage(), e);
        }
        if (verify) logger.info("微信公众平台验证成功");
        return echostr;
    }

    /**
     * 微信公众平台事件或者消息的推送接收(扫码关注与取消关注) 后续可用于自定义菜单获取验证码,票据什么的
     *
     * @param appid 公众号的APPID
     *              集成参考链接，回调的地址需要在微信公众平台开发者中心处设置的服务器地址
     *              <a href="https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html">...</a>
     */
    @PostMapping(value = "wxUtil/wxGzNotify/{appid}", produces = "application/xml;charset=UTF-8")
    public void wxGzNotify(@PathVariable String appid) {
        try {
            Bson map = WxUtil.handReqData();
            map.put("appid", appid);
            logger.info("微信公众号消息参数通知:" + Bson.toString(map));
            String msgType = map.getString("MsgType"); // 消息类型 event 事件 text 文本 image 图片 voice 语音 video 视频
            String gzhName = map.getString("ToUserName"); // 公众号名称 用作回复使用
            String openId = map.getString("FromUserName"); // openId
            String event = map.getString("Event"); // 事件类型，subscribe(订阅)、unsubscribe(取消订阅)
            String eventKey = map.getString("EventKey"); //
            if (msgType.equals("event")) { // 事件类消息
                switch (event) {
                    case "subscribe":  // subscribe(订阅) 关注订阅 eventKey如果是扫描二维码关注,则存在该参数 由两部分构成
                        String code = Assert.isBlank(eventKey) ? null : eventKey.split("_")[1]; // 二维码生成时的参数
                        if (Assert.notBlank(code)) { // 扫码关注
                            logger.info("扫码关注=====>" + code);
                        }else{
                            logger.info("直接关注==>"+eventKey);
                        }
                        break;
                    case "unsubscribe":  // 取消关注
                        logger.info("取消关注====>" );
                        break;
                    case "SCAN":  // 已关注的扫码事件(一般不需要用到该场景值)
                        logger.info("已关注的扫码事件===>" + eventKey);
                        break;
                    case "CLICK":
                        logger.info("菜单点击事件===》" + eventKey); // click菜单带有的值
                        if(Assert.notBlank(eventKey)){
                            if (eventKey.equalsIgnoreCase("lian_xi_wo_men")) {

                            } else if (eventKey.equalsIgnoreCase("yi_ji_wo_men")) {

                            }else {

                            }
                        }
                        break;
                }
            } else if (msgType.equals("text")) { // 文本类消息
                String content = map.getString("Content");
                logger.info("文本消息内容:" + content);
            }
        } catch (Exception e) {
            logger.error("服务异常:" + e.getMessage(), e);
        }
    }

    @PostMapping("/wxPayV3Notify")
    public Bson wxPayV3Notify (@RequestBody Bson params) {
        Bson result = WxUtil.wxPayV3Notify(params,"LTAI5tR8C8AsigUx4P56fuqiao202412");
        logger.info("微信回调参数:"+result.getBson("callback"));
        return result.getBson("wxRes");
    }
}
